import { RuntimeError, IMarkOpenData } from '@ibiz-template/core';
import {
  ViewEngineBase,
  ViewController,
  IEditFormController,
  SysUIActionTag,
  EventBase,
  IEditViewState,
  IEditViewEvent,
  ControlVO,
  calcDeCodeNameById,
  OpenAppViewCommand,
  IModalData,
  getAppViewRef,
  ViewCallTag,
  getControl,
  getControlsByView,
  MarkOpenDataActionType,
  ViewMode,
  IPanelItemCoopPosController,
} from '@ibiz-template/runtime';
import { IAppDEEditView } from '@ibiz/model-core';

export class EditViewEngine extends ViewEngineBase {
  /**
   * 视图控制器
   *
   * @protected
   * @type {ViewController<
   *     IAppDEEditView,
   *     IEditViewState,
   *     IEditViewEvent
   *   >}
   * @memberof EditViewEngine
   */
  protected declare view: ViewController<
    IAppDEEditView,
    IEditViewState,
    IEditViewEvent
  >;

  get form(): IEditFormController {
    return this.view.getController('form') as IEditFormController;
  }

  get coopPos(): IPanelItemCoopPosController | undefined {
    return this.view.layoutPanel?.panelItems
      .coop_pos as IPanelItemCoopPosController;
  }

  /**
   * 实体名称
   * @author lxm
   * @date 2024-01-31 11:05:49
   * @type {string}
   */
  deName!: string;

  protected init(): void {
    super.init();
    if (this.view.model.multiFormMode === 1 && this.view.params.srfdatatype) {
      const model = getControl(
        this.view.model,
        `_form_${this.view.params.srfdatatype}`,
      );
      if (model) {
        const controls = getControlsByView(this.view.model).filter(item => {
          return item.controlType !== 'FORM';
        });
        model.name = 'form';
        controls.push(model);
        if (this.view.model.viewLayoutPanel) {
          this.view.model.viewLayoutPanel.controls = controls;
        } else {
          this.view.model.controls = controls;
        }
      }
    }
  }

  async onCreated(): Promise<void> {
    await super.onCreated();
    const { childNames, modal } = this.view;
    childNames.push('form');

    this.deName = calcDeCodeNameById(this.view.model.appDataEntityId!);

    // 给表单加默认不加载
    if (!this.view.slotProps.form) {
      this.view.slotProps.form = {};
    }
    this.view.slotProps.form.loadDefault = false;

    // 给工具栏加默认不计算状态
    if (!this.view.slotProps.toolbar) {
      this.view.slotProps.toolbar = {};
    }
    this.view.slotProps.toolbar.manualCalcButtonState = true;

    modal.hooks.shouldDismiss.tapPromise(async context => {
      const uiDomain = ibiz.uiDomainManager.get(this.view.context.srfsessionid);
      const isChange =
        (this.form.state.modified || uiDomain.dataModification) &&
        this.view.model.enableDirtyChecking === true;
      if (isChange && context.allowClose == null) {
        const isAllow = await ibiz.confirm.error({
          title: '关闭提醒',
          desc: '表单数据已经修改，确定要关闭？',
        });
        if (!isAllow) {
          context.allowClose = false;
        } else {
          context.allowClose = true;
        }
      }
    });
  }

  async onMounted(): Promise<void> {
    await super.onMounted();

    this.initMarkOpenData();

    const { model, evt } = this.view;

    // 监控form事件
    const formDeId = this.form.model.appDataEntityId;
    const formDataStateChange = (event: EventBase): void => {
      const data = event.data[0];
      this.toolbar?.calcButtonState(data, formDeId);
      if (model.showDataInfoBar) {
        if (data.srfkey) {
          evt.emit('onViewInfoChange', { dataInfo: data.srfmajortext || '' });
        } else {
          evt.emit('onViewInfoChange', { dataInfo: '新建' });
        }
      }
    };

    this.form.evt.on('onLoadSuccess', event => {
      formDataStateChange(event);
      // 更新视图作用域数据
      this.view.state.srfactiveviewdata = event.data[0];
      evt.emit('onDataChange', { ...event, actionType: 'LOAD' });
    });
    this.form.evt.on('onLoadDraftSuccess', event => {
      formDataStateChange(event);
      evt.emit('onDataChange', { ...event, actionType: 'LOADDRAFT' });
    });
    this.form.evt.on('onSaveSuccess', event => {
      this.view.state.closeOK = true;
      const deName = calcDeCodeNameById(this.view.model.appDataEntityId!);
      const formData = event.data[0];
      if (this.view.context[deName] !== formData.srfkey) {
        this.view.context[deName] = formData.srfkey;
      }
      formDataStateChange(event);
      evt.emit('onDataChange', { ...event, actionType: 'SAVE' });
    });
    this.form.evt.on('onRemoveSuccess', event => {
      formDataStateChange(event);
      evt.emit('onDataChange', { ...event, actionType: 'REMOVE' });
    });

    if (!this.view.state.noLoadDefault && model.loadDefault) {
      this.load();
    }
  }

  getData(): IData[] {
    return this.form.getData();
  }

  async load(): Promise<IData> {
    return this.form.load();
  }

  async save(): Promise<IData> {
    return this.form.save();
  }

  async refresh(): Promise<void> {
    this.form.doNextActive(() => this.load(), { key: 'load' });
  }

  // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
  async call(key: string, args: any): Promise<any> {
    if (key === SysUIActionTag.SAVE) {
      await this.form.save();
      return null;
    }
    if (key === SysUIActionTag.SAVE_AND_EXIT) {
      await this.form.save();
      return { closeView: true };
    }
    if (key === SysUIActionTag.REMOVE_AND_EXIT) {
      const res = await this.form.remove();
      return { closeView: res };
    }
    if (key === SysUIActionTag.SAVE_AND_NEW) {
      this.saveAndNew();
      return null;
    }
    if (key === SysUIActionTag.REFRESH) {
      await this.refresh();
      return null;
    }
    if (key === SysUIActionTag.SAVE_AND_START) {
      await this.wfStart();
      return null;
    }
    if (
      key === SysUIActionTag.FIRST_RECORD ||
      key === SysUIActionTag.LAST_RECORD ||
      key === SysUIActionTag.PREV_RECORD ||
      key === SysUIActionTag.NEXT_RECORD
    ) {
      await this.changeRecord(key);
      return null;
    }
    if (key === SysUIActionTag.VIEW_WF_STEP) {
      await this.wfSubmit();
      return null;
    }
    if (key === ViewCallTag.LOAD) {
      this.load();
      return null;
    }
    if (key === ViewCallTag.VALIDATE) {
      return this.form.validate();
    }
    if (key === ViewCallTag.WF_WITHDRAW) {
      await this.wfWithdraw();
    }
    return super.call(key, args);
  }

  /**
   * 保存并新建
   *
   * @author zk
   * @date 2023-06-01 01:06:59
   * @return {*}
   * @memberof EditViewEngine
   */
  async saveAndNew(): Promise<void> {
    await this.form.save();
    this.form.state.data = new ControlVO();
    // 置空主键
    this.view.context[calcDeCodeNameById(this.view.model.appDataEntityId!)] =
      undefined;
    await this.form.load();
  }

  /**
   * 工作流启动
   *
   * @author lxm
   * @date 2022-09-29 20:09:27
   * @returns {*}  {Promise<void>}
   */
  async wfStart(): Promise<void> {
    // 先保存
    await this.save();

    const entityService = await ibiz.hub.getAppDEService(
      this.view.model.appId,
      this.view.model.appDataEntityId!,
      this.view.context,
    );

    const data = this.form.state.data;

    // *获取工作流版本信息
    const res = await entityService.wf.getWFVersion(
      data.srfwftag ?? this.view.params.srfwftag ?? this.view.context.srfwftag,
    );
    if (res.data.length === 0) {
      throw new RuntimeError('当前工作流版本不存在');
    }
    // todo 多个的情况要出一个确认框选择后走后续逻辑

    const wfInfo = res.data[0];
    const refKey = `WFSTART@${wfInfo.wfversion}`;

    // 处理视图上下文
    const newContext = Object.assign(this.view.context.clone(), {
      activeForm: wfInfo['process-form'],
    });
    // 处理视图参数
    const newParams = {
      processDefinitionKey: wfInfo.definitionkey,
    };

    // 查找工作流启动视图
    const startView = getAppViewRef(this.view.model, refKey);

    // *没有工作流启动视图的，自己启动工作流
    if (!startView) {
      await this.form.wfStart({ viewParam: newParams });
      await this.view.closeView();
      return;
    }

    // *有工作流启动视图的，由启动视图执行工作流启动
    const result: IModalData = await ibiz.commands.execute(
      OpenAppViewCommand.TAG,
      startView.refAppViewId,
      newContext,
      newParams,
    );

    // 启动视图正常关闭后关闭当前视图
    if (result.ok) {
      await this.view.closeView();
    }
  }

  /**
   * 工作流提交
   *
   * @author lxm
   * @date 2022-09-29 20:09:27
   * @returns {*}  {Promise<void>}
   */
  wfSubmit(): Promise<void> {
    return this.form.wfSubmit();
  }

  /**
   * 工作流撤回
   *
   * @author zk
   * @date 2023-11-22 11:11:55
   * @return {*}  {Promise<void>}
   * @memberof MobEditViewEngine
   */
  async wfWithdraw(): Promise<void> {
    const app = ibiz.hub.getApp(this.view.context.srfappid);
    const data = this.form.state.data;
    const entityService = await app.deService.getService(
      this.view.context,
      this.view.model.appDataEntityId!,
    );
    await entityService.wf.exec(
      'withdraw',
      this.view.context,
      {
        ...this.view.params,
        taskId: this.view.params.taskId || this.view.params.srftaskid,
      },
      data instanceof ControlVO ? data.getOrigin() : data,
    );
    // 刷新预定义todo实体数据
    ibiz.mc.command.send(
      { srfdecodename: 'SysTodo' },
      'OBJECTUPDATED',
      'WITHDRAW',
    );
  }

  /**
   * 初始化标记打开数据相关逻辑
   * @author lxm
   * @date 2024-01-31 11:52:13
   * @return {*}  {void}
   */
  initMarkOpenData(): void {
    // 非路由的编辑视图不需要触发（防止多个界面同时操作一条数据，消息重复）
    if (
      ![ViewMode.ROUTE, ViewMode.ROUTE_MODAL].includes(this.view.modal.mode) ||
      !this.view.model.markOpenDataMode
    ) {
      return;
    }

    const modes = this.view.model.markOpenDataMode!.split(';');
    let hasOpenConfirm = false;

    const callback = async (data: IMarkOpenData) => {
      // 非激活不触发提示
      if (!this.view.state.activated) {
        return;
      }

      const dataInfo = this.form.getData()[0].srfmajortext;

      let actionMsg = '';
      switch (data.action) {
        case 'VIEW':
          actionMsg = '浏览了';
          break;
        case 'EDIT':
          actionMsg = '编辑了';
          break;
        case 'UPDATE':
          actionMsg = '更新了';
          break;
        default:
          break;
      }

      const message = `${
        modes.includes('DISPLAYOPPERSON') ? data.username : '有人'
      } ${actionMsg} ${this.view.state.caption}-${dataInfo}`;

      if (this.coopPos) {
        this.coopPos.updateMessage({
          title: message,
        });
      } else {
        ibiz.message.notice({
          message,
          showClose: true,
          duration: 3,
          styleType: 'alert',
        });
      }

      if (
        hasOpenConfirm === false &&
        data.action === 'UPDATE' &&
        modes.includes('NOTICERELOAD')
      ) {
        hasOpenConfirm = true;
        const isReload = await this.reloadConfirm();
        if (isReload) {
          this.refresh();
        }
        hasOpenConfirm = false;
      }
    };

    // OPENDATA：登记打开数据、 EDITDATA：登记更新数据、 DISPLAYOPPERSON：显示操作人员、 NOTICERELOAD：提示刷新数据
    // *触发markopendata行为控制
    const doActions: MarkOpenDataActionType[] = [];
    if (
      modes.includes('EDITDATA') ||
      modes.includes('DISPLAYOPPERSON') ||
      modes.includes('NOTICERELOAD')
    ) {
      doActions.push('EDIT', 'VIEW', 'UPDATE', 'CLOSE');
    } else if (modes.includes('OPENDATA')) {
      doActions.push('VIEW', 'CLOSE');
    }

    // 没有配置就不监听了
    if (doActions.length === 0) {
      return;
    }

    let srfkey: string | undefined;
    let hasSubscribe = false;

    if (doActions.includes('VIEW')) {
      this.form.evt.on('onLoadSuccess', event => {
        const formData = event.data[0];
        srfkey = formData.srfkey;
        ibiz.markOpenData.action(this.deName, srfkey!, 'VIEW');
        // 只监听一次
        if (!hasSubscribe) {
          ibiz.markOpenData.subscribe(this.deName, srfkey!, callback);
          this.view.evt.on('onDestroyed', () => {
            ibiz.markOpenData.unsubscribe(this.deName, srfkey!, callback);
          });
          hasSubscribe = true;
        }
      });
    }

    if (doActions.includes('EDIT')) {
      let isWait = false;
      const actionEdit = () => {
        if (!srfkey || isWait) {
          return;
        }
        isWait = true;
        ibiz.markOpenData.action(this.deName, srfkey, 'EDIT');
        setTimeout(
          () => {
            isWait = false;
          },
          1000 * 60 * 5,
        );
      };

      this.form.evt.on('onFormDataChange', actionEdit);
    }

    if (doActions.includes('UPDATE')) {
      this.form.evt.on('onSaveSuccess', () => {
        if (srfkey) {
          ibiz.markOpenData.action(this.deName, srfkey, 'UPDATE');
        }
      });
    }

    if (doActions.includes('CLOSE')) {
      this.view.evt.on('onCloseView', () => {
        if (srfkey) {
          ibiz.markOpenData.action(this.deName, srfkey, 'CLOSE');
        }
      });
    }
  }

  /**
   * 刷新确认
   * @author lxm
   * @date 2024-02-06 11:40:36
   * @return {*}  {Promise<boolean>}
   */
  async reloadConfirm(): Promise<boolean> {
    const result = await ibiz.confirm.info({
      title: '是否刷新',
      desc: '数据已被修改是否刷新页面？',
    });
    if (result && this.form.state.modified) {
      return ibiz.confirm.warning({
        title: '刷新提醒',
        desc: '表单数据已经修改，确定要刷新？',
      });
    }
    return result;
  }

  /**
   * 变更当前页面的数据
   * @author lxm
   * @date 2024-04-01 01:11:58
   * @param {string} type
   */
  async changeRecord(type: string): Promise<void> {
    const viewId = this.view.context.srfpaginationviewid;
    if (!viewId) {
      throw new RuntimeError('context缺少srfpaginationviewid');
    }
    const view = ibiz.util.viewStack.getView(viewId);
    if (!view) {
      throw new RuntimeError(`找不到id是${viewId}的视图`);
    }
    const items = (await view.call(ViewCallTag.GET_ALL_DATA)) as IData[];
    const index = items.findIndex(
      item => item.srfkey === this.form.state.data.srfkey,
    );
    let targetItem: IData | undefined;
    switch (type) {
      case SysUIActionTag.FIRST_RECORD:
        if (index === 0) {
          ibiz.message.info('已经是第一条数据了');
          return;
        }
        targetItem = items[0];
        break;
      case SysUIActionTag.LAST_RECORD:
        if (index === items.length - 1) {
          ibiz.message.info('已经是最后一条数据了');
          return;
        }
        targetItem = items[items.length - 1];
        break;
      case SysUIActionTag.PREV_RECORD:
        if (index === 0) {
          ibiz.message.info('已经是第一条数据了');
          return;
        }
        targetItem = items[index - 1];
        break;
      case SysUIActionTag.NEXT_RECORD:
        if (index === items.length - 1) {
          ibiz.message.info('已经是最后一条数据了');
          return;
        }
        targetItem = items[index + 1];
        break;
      default:
        break;
    }

    // 变更主键并加载
    if (targetItem) {
      this.view.context[this.deName] = targetItem.srfkey;
      this.load();
    }
  }
}
